System user authentication via web interface [closed]

Posted by donodarazao on Server Fault See other posts from Server Fault or by donodarazao
Published on 2011-02-21T14:21:00Z Indexed on 2011/02/21 15:27 UTC
Read the original article Hit count: 253

Background:

We have one pretty slow and expensive satellite Internet connection that is shared in a network with 5-50 users. To limit traffic, users shall pay a certain sum of money per hour. Routing and traffic accounting on user basis is done by a opensuse 10.3 server. Login is done via pppoe, and for each connection, username, bytes_sent, bytes_rcvd, start_time, end_time,etc are written into a mysql database.

Now it was decided that we want to change from time-based to volume-based pricing. As the original developer who installed the system a couple of years ago isn't available, I'm trying to do the changes. Although I'm absolutely new to all this, there is some progress. However, there's one point I'm absolutely stuck.

Up to now, only administrators can access connection details and billing information via a web interface. But as volume-based prices are less transparent to users than time-based prices, it is essential that users themselves can check their connections and how much they cost via the web interface. For this, we need some kind of user authentication.

Actual question:

How to develop such a user authentication? Every user has a linux system user account. With this user name and password, connection to the pppoe-server is made by the client machines. I thought about two possibles ways to authenticate users:

First possibility: Users type username and password in a form. This is then somehow checked. We already have to possibilities to change passwords via the web interface. Here are parts of the code:

Part of the Perl script the homepage is linked to:

#!/usr/bin/perl

use CGI;
use CGI::Carp qw(fatalsToBrowser);

use lib '../lib';
use own_perl_module;

my @error;
my $data;

$query = new CGI;
$username  = $query->param('username') || '';
$oldpasswd = $query->param('oldpasswd') || '';
$passwd    = $query->param('passwd') || '';
$passwd2   = $query->param('passwd2') || '';

own_perl_module::connect();

if ($query->param('submit')) {
    my $benutzer = own_perl_module::select_benutzer(username => $username) or push @error, "user not exists";
    push @error, "your password?!?" unless $passwd;

    unless (@error) {
        own_perl_module::update_benutzer($benutzer->{id}, { oldpasswd => $oldpasswd, passwd => $passwd, passwd2 => $passwd2 }, error => \@error)
            and push @error, "Password changed.";
    }
}

Here's part of the sub update_benutzer in the own_perl_module:

if ($dat->{passwd} ne '') { my $username = $dat->{username} || $select->{username}; my $system = "./chpasswd.pl '$username' '$dat->{passwd}'" . (defined($dat->{oldpasswd}) ? " '$dat->{oldpasswd}'" : undef); my $answer = $system; if ($? != 0) { chomp($answer); push @$error, $answer || "error changing password ($?)";

Here's chpasswd.pl:

#!/usr/bin/perl

use FileHandle;
use IPC::Open3;

local $username = shift;
local $passwd = shift;
local $oldpasswd = shift;

local $chat = { 'Old Password: $' => sub { print POUT "$oldpasswd\n"; },
                'New password: $' => sub { print POUT "$passwd\n"; },
                'Re-enter new password: $' => sub { print POUT "$passwd\n"; },
                '(.*)\n$' => sub { print "$1\n"; exit 1; } };

local $/ = \1;

my $command;
if (defined($oldpasswd)) {
    $command = "sudo -u '$username' /usr/bin/passwd";
} else {
    $command = "sudo /usr/bin/passwd '$username'";
}

$pid = open3(\*POUT, \*PIN, \*PERR, $command) or die;

my $buffer;
LOOP: while($_ = <PERR>) {
    $buffer .= $_;
    foreach (keys(%$chat)) {
        if ($buffer =~ /$_/i) {
            $buffer = undef;
            &{$chat->{$_}}; 
        }
    }
}

exit;

Could this somehow be adjusted to verify users, but not changing user passwords?

The second possibility I see: all pppoe connections are logged in the mysql database. If I could somehow retrieve the username (or uid) of the user connected by pppoe, this could be used to authenticate users. Users could only check their internet connections and costs when they are online (and thus paying money), but this could be tolerated.

Here's a line of the script that inserts connections into the database:

my $username = $ENV{PEERNAME};

I thought it would be easy to use this variable, but $username seems to be always empty in test-scripts (print $username). Any idea how to retrieve the user connected to the pppoe server?

Sorry for the long question! Any help would be very much appreciated. :)

© Server Fault or respective owner

Related posts about server

Related posts about authentication